package com.jplus.core.plugin.aspect;

import java.lang.reflect.Method;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.jplus.core.core.proxys.Proxy;
import com.jplus.core.core.proxys.ProxyChain;

/**
 * 【核心插件】切面拦截<br>
 * AOP的实现基于插件, 自定义拦截器请 继承改类;<br>
 * 没使用抽象是想让用户自己控制
 */
public abstract class MethodInterceptor implements Proxy {

	private static final Logger logger = LoggerFactory.getLogger(MethodInterceptor.class);
	private ThreadLocal<ProxyChain> proxyChains = new ThreadLocal<>();

	protected ProxyChain getProxyChain() {
		return proxyChains.get();
	}

	@Override
	public final Object doProxy(ProxyChain proxyChain) throws Throwable {
		Aspect aspect = proxyChain.getProxy().getClass().getAnnotation(Aspect.class);
		Object result = null;
		if (ExecutionKit.analysis(proxyChain.getTargetMethod(), aspect)) { // 判断当前方法是否拦截
			proxyChains.set(proxyChain);
			Class<?> cls = proxyChain.getTargetClass();
			Method method = proxyChain.getTargetMethod();
			Object[] params = proxyChain.getMethodParams();

			begin();// 1.开始
			try {
				if (intercept(cls, method, params)) {// 2.前拦截
					before(cls, method, params);// 3.前
					result = around(proxyChain);// 4.环绕拦截
					after(cls, method, params, result);// 5.后
				}
			} catch (Exception e) {
				logger.error("AOP 异常", e);
				error(cls, method, params, e);// 6.异常
				throw e;
			} finally {
				end();// 7.结束
			}
		} else {
			result = proxyChain.doProxyChain();
		}
		return result;
	}

	// =====================================================

	/**
	 * 开始拦截[一定执行]
	 */
	public void begin() {
	}

	/**
	 * 阻断拦截
	 * 
	 * @param cls
	 *            方法所在类
	 * @param method
	 *            方法对象
	 * @param params
	 *            方法入参
	 * @return true:继续执行；false:阻断执行
	 * @throws Throwable
	 *             拦截异常
	 */
	public boolean intercept(Class<?> cls, Method method, Object[] params) throws Throwable {
		return true;
	}

	/**
	 * 前拦截
	 * 
	 * @param cls
	 *            方法所在类
	 * @param method
	 *            方法对象
	 * @param params
	 *            方法入参
	 * @throws Throwable
	 *             拦截异常
	 */
	public void before(Class<?> cls, Method method, Object[] params) throws Throwable {
	}

	/**
	 * 环绕拦截
	 * 
	 * @param proxyChain
	 *            代理链对象
	 * @return 方法执行结果
	 * @throws Throwable
	 *             拦截异常
	 */
	public Object around(ProxyChain proxyChain) throws Throwable {
		return proxyChain.doProxyChain();
	}

	/**
	 * 后拦截
	 * 
	 * @param cls
	 *            方法所在类
	 * @param method
	 *            方法对象
	 * @param params
	 *            方法入参
	 * @return result 方法执行结果
	 * @throws Throwable
	 *             拦截异常
	 */
	public void after(Class<?> cls, Method method, Object[] params, Object result) throws Throwable {
	}

	/**
	 * 异常拦截
	 * 
	 * @param cls
	 *            方法所在类
	 * @param method
	 *            方法对象
	 * @param params
	 *            方法入参
	 * @param e
	 *            方法返回异常
	 */
	public void error(Class<?> cls, Method method, Object[] params, Throwable e) {
	}

	/**
	 * 结束拦截
	 */
	public void end() {
	};
}
